package com.nnnu.wsnackshop.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nnnu.wsnackshop.pojo.entity.Users;
import com.nnnu.wsnackshop.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class NotificationWebSocketHandler extends TextWebSocketHandler {

    private static final Map<String, WebSocketSession> ADMIN_SESSIONS = new ConcurrentHashMap<>();
    private static final Map<String, Integer> SESSION_USER_IDS = new ConcurrentHashMap<>();
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public void afterConnectionEstablished(WebSocketSession session) {
        // 用户ID应该从session属性中获取，这里简化处理
        String sessionId = session.getId();
        ADMIN_SESSIONS.put(sessionId, session);

        // 发送连接成功消息
        try {
            Map<String, Object> message = Map.of(
                    "type", "CONNECTION_SUCCESS",
                    "message", "WebSocket连接已建立",
                    "timestamp", System.currentTimeMillis());

            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(message)));
        } catch (Exception e) {
            log.error("发送连接成功消息失败: {}", e.getMessage());
        }
    }

    @Override
    protected void handleTextMessage(@NotNull WebSocketSession session, TextMessage message) {
        // 解析消息
        String payload = message.getPayload();

        try {
            Map<String, Object> messageMap = objectMapper.readValue(payload, Map.class);
            String messageType = (String) messageMap.get("type");

            // 处理不同类型的消息
            if ("AUTH".equals(messageType)) {
                handleAuthMessage(session, messageMap);
            }
        } catch (Exception e) {
            log.error("处理WebSocket消息失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 处理认证消息
     */
    private void handleAuthMessage(WebSocketSession session, Map<String, Object> messageMap) {
        try {
            String token = (String) messageMap.get("token");
            if (token == null) {
                return;
            }

            // 验证token
            Users user = JwtUtil.getUserFromToken(token);
            if (user != null && user.getId() != null) {
                // 保存用户ID与会话的映射
                SESSION_USER_IDS.put(session.getId(), user.getId());

                // 发送认证成功消息
                Map<String, Object> response = Map.of(
                        "type", "AUTH_SUCCESS",
                        "userId", user.getId(),
                        "username", user.getUsername(),
                        "timestamp", System.currentTimeMillis());

                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
            } else {
                log.warn("认证失败: token无效或无法解析用户信息");
            }
        } catch (Exception e) {
            log.error("处理认证消息失败: {}", e.getMessage(), e);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, @NotNull CloseStatus status) {
        String sessionId = session.getId();
        ADMIN_SESSIONS.remove(sessionId);
        SESSION_USER_IDS.remove(sessionId);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) {
        log.error("WebSocket传输错误: {}", exception.getMessage(), exception);
    }

    /**
     * 向所有管理员发送订单分配通知
     * 
     * @param orderId 订单ID
     * @param message 通知消息
     */
    public void sendOrderAssignmentNotification(Long orderId, String message) {
        try {
            Map<String, Object> notification = Map.of(
                    "type", "ORDER_ASSIGNMENT",
                    "orderId", orderId,
                    "message", message,
                    "timestamp", System.currentTimeMillis());

            String notificationJson = objectMapper.writeValueAsString(notification);
            TextMessage textMessage = new TextMessage(notificationJson);

            for (WebSocketSession session : ADMIN_SESSIONS.values()) {
                if (session.isOpen()) {
                    try {
                        session.sendMessage(textMessage);
                        log.info("已向管理员 {} 发送订单分配通知", session.getId());
                    } catch (IOException e) {
                        log.error("发送通知失败: {}", e.getMessage(), e);
                    }
                }
            }
        } catch (Exception e) {
            log.error("准备通知消息失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 静态方法，方便其他服务调用发送通知
     */
    public static void notifyOrderNeedsRider(Long orderId, String orderNo) {
        // 这个方法会在Spring上下文外部调用，因此不能直接使用bean
        // 需要通过ApplicationContext获取bean实例
        NotificationWebSocketHandler handler = ApplicationContextProvider.getBean(NotificationWebSocketHandler.class);
        String message = "订单 #" + orderNo + " 需要分配骑手";
        handler.sendOrderAssignmentNotification(orderId, message);
    }

    /**
     * 向用户发送订单自提通知
     * 
     * @param userId  用户ID
     * @param orderId 订单ID
     * @param orderNo 订单编号
     */
    public void sendPickupReadyNotification(Integer userId, Long orderId, String orderNo) {
        try {
            Map<String, Object> notification = Map.of(
                    "type", "PICKUP_READY",
                    "orderId", orderId,
                    "orderNo", orderNo,
                    "message", "您的订单 #" + orderNo + " 已准备好，可以前来自提了",
                    "timestamp", System.currentTimeMillis());

            String notificationJson = objectMapper.writeValueAsString(notification);
            TextMessage textMessage = new TextMessage(notificationJson);

            // 查找用户的WebSocket会话
            for (Map.Entry<String, WebSocketSession> entry : ADMIN_SESSIONS.entrySet()) {
                String sessionId = entry.getKey();
                WebSocketSession session = entry.getValue();

                // 检查会话是否属于目标用户
                Integer sessionUserId = SESSION_USER_IDS.get(sessionId);
                if (sessionUserId != null && sessionUserId.equals(userId) && session.isOpen()) {
                    try {
                        session.sendMessage(textMessage);
                        log.info("已向用户 {} 发送订单自提通知", userId);
                    } catch (IOException e) {
                        log.error("发送通知失败: {}", e.getMessage(), e);
                    }
                }
            }
        } catch (Exception e) {
            log.error("准备通知消息失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 静态方法，方便其他服务调用发送自提通知
     */
    public static void notifyOrderReadyForPickup(Integer userId, Long orderId, String orderNo) {
        // 这个方法会在Spring上下文外部调用，因此不能直接使用bean
        // 需要通过ApplicationContext获取bean实例
        NotificationWebSocketHandler handler = ApplicationContextProvider.getBean(NotificationWebSocketHandler.class);
        handler.sendPickupReadyNotification(userId, orderId, orderNo);
    }
}